package com.freedy.concurrent.Monitors.patterns;


import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;

import java.util.LinkedList;


/**
 * 异步模式之生产者/消费者
 * @author Freedy
 * @date 2021/4/22 16:31
 */
@Slf4j
public class ProducerConsumer {
    public static void main(String[] args) {
        MessageQueue queue = new MessageQueue(3);
        for (int i = 1; i <= 10; i++) {
            int finalI = i;
            new Thread(() ->{
                log.info("生产者{} 开始发送消息", finalI);
                queue.put(new Message(finalI,
                        "lovlove you hahae yolove you hahau hlove you hahaahalove you haha".
                                substring(finalI,finalI*5)));
                log.info("生产者{}----->消息发送成功<-----", finalI);
            }, "生产者" + i).start();
        }
        new Thread(() -> {
            for (;;) {
                try {
                    Thread.sleep(1000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println();
                log.info("接受到消息{}",queue.take());
            }
        }, "消费者").start();
    }
}

/**
 * 消息队列类 java线程之间的通讯
 */
@Slf4j
@AllArgsConstructor
class MessageQueue {
    private final LinkedList<Message> list = new LinkedList<>();
    private final int capacity;

    /**
     * 获取消息
     */
    public Message take() {
        synchronized (list) {
            while (list.isEmpty()) {
                try {
                    //log.info("队列为空等待发送消息");
                    list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            list.notifyAll();
            return list.pop();
        }
    }

    /**
     * 存放消息
     */
    public void put(Message message) {
        synchronized (list) {
            //检查队列是否已满
            while (list.size() == capacity) {
                try {
                    //log.info("队列已满等待接受消息");
                    list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            list.add(message);
            list.notifyAll();
        }
    }

}

@Getter
@AllArgsConstructor
@ToString
final class Message {
    private final int id;
    private final Object value;
}